package tencent

import (
	"context"
	e "errors"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	captcha "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/captcha/v20190722"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)

var Captcha = &captcha2{}

type captcha2 struct {
	configs []*captchaConfig
}

type captchaConfig struct {
	Name      string
	AppId     string
	AppSecret string
}

// CaptchaTicket 腾讯验证后返回的数据，注意 ClientIP 需要自己设置为客户端的IP
type CaptchaTicket struct {
	BizState string `json:"bizState"`
	Appid    string `json:"appid"`
	Ret      int    `json:"ret"`
	Ticket   string `json:"ticket"`
	Randstr  string `json:"randstr"`
	ClientIP string `json:"ip"`
}

func init() {
	Captcha.init()
}

func (r *captcha2) init() {
	m := g.Config().MustGet(context.Background(), "app.tencent.captchas.captcha")
	m.Scan(&r.configs)
}

func (r *captcha2) getConfigByAppId(appId string) *captchaConfig {
	for _, c := range r.configs {
		if c.AppId == appId {
			return c
		}
	}
	return nil
}

func (r *captcha2) VerifyTicket(ticket *CaptchaTicket) (bool, error) {
	c := r.getConfigByAppId(ticket.Appid)
	if c == nil {
		return false, e.New("invalid app id")
	}

	credential := Config.NewCredential()
	// 实例化一个client选项，可选的，没有特殊需求可以跳过
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "captcha.tencentcloudapi.com"
	// 实例化要请求产品的client对象,clientProfile是可选的
	client, _ := captcha.NewClient(credential, "", cpf)

	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := captcha.NewDescribeCaptchaResultRequest()

	request.CaptchaType = common.Uint64Ptr(9)
	request.Ticket = common.StringPtr(ticket.Ticket)
	request.UserIp = common.StringPtr(ticket.ClientIP)
	request.Randstr = common.StringPtr(ticket.Randstr)
	request.CaptchaAppId = common.Uint64Ptr(gconv.Uint64(ticket.Appid))

	request.AppSecretKey = common.StringPtr(c.AppSecret)
	request.NeedGetCaptchaTime = common.Int64Ptr(1)

	// 返回的resp是一个DescribeCaptchaResultResponse的实例，与请求对象对应
	response, err := client.DescribeCaptchaResult(request)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		return false, err
	}
	if err != nil {
		return false, err
	}
	//glog.Info(context.Background(), response.ToJsonString())
	/*
		{"Response":{"CaptchaCode":1,"CaptchaMsg":"OK","EvilLevel":0,"GetCaptchaTime":1669356121,"RequestId":"13d97167-885b-4e79-a35e-249a23a5fdba"}}
	*/

	/*
		1 OK 验证通过
		7 captcha no match 传入的Randstr不合法，请检查Randstr是否与前端返回的Randstr一致
		8 ticket expired 传入的Ticket已过期（Ticket有效期5分钟），请重新生成Ticket、Randstr进行校验
		9 ticket reused 传入的Ticket被重复使用，请重新生成Ticket、Randstr进行校验
		15 decrypt fail 传入的Ticket不合法，请检查Ticket是否与前端返回的Ticket一致
		16 appid-ticket mismatch 传入的CaptchaAppId错误，请检查CaptchaAppId是否与前端传入的CaptchaAppId一致，并且保障CaptchaAppId是从验证码控制台【验证管理】->【基础配置】中获取
		21 diff 票据校验异常，可能的原因是（1）若Ticket包含terror前缀，一般是由于用户网络较差，导致前端自动容灾，而生成了容灾票据，业务侧可根据需要进行跳过或二次处理。（2）若Ticket不包含terror前缀，则是由于验证码风控系统发现请求有安全风险，业务侧可根据需要进行拦截。
		100 appid-secretkey-ticket mismatch 参数校验错误，（1）请检查CaptchaAppId与AppSecretKey是否正确，CaptchaAppId、AppSecretKey需要在验证码控制台【验证管理】>【基础配置】中获取（2）请检查传入的Ticket是否由传入的CaptchaAppId生成
	*/
	if *response.Response.CaptchaCode == 1 {
		/*
			无感验证模式下，该参数返回验证结果：
			EvilLevel=0 请求无恶意
			EvilLevel=100 请求有恶意
			注意：此字段可能返回 null，表示取不到有效值。
		*/
		res := *response.Response.EvilLevel == 0
		return res, nil
	}
	return false, nil
}
